/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.usfirst.frc2084.robotsimulator.gui;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Changes imports and packages of Java files to be compatible with the ported
 * version of WPILibJ and the storage of robot code files in the simulator.
 *
 * @author Sam
 */
public final class CodeCleaner {

    /**
     * The default WPILibJ path.
     */
    public static final String WPILIBJ_PATH = "edu.wpi.first.wpilibj";
    /**
     * Where the ported version of WPILibJ is located. (Currently equivalent to
     * the default; may get changed later, but that's a minor detail.)
     */
    public static final String PORTED_WPILIBJ_PATH = "edu.wpi.first.wpilibj";
    /**
     * Where users' robot code is located in the simulator. This is added to the
     * beginning of imports in users' code.
     */
    public static final String CODE_LOCATION = "code.";
    /**
     * An addendum to cleaned files to make sure we don't clean them again.
     */
    public static final String ADDENDUM = "//CodeCleaner -- do not edit this line";

    /**
     * Cleans up the imports of a Java robot code file, or all Java files within
     * a directory (including children). Should only be called once, on the
     *
     * @param file The file or directory to clean up.
     */
    public static void cleanDirectory(File file) {
        if (file.getName().endsWith(".java")) { // only go over java files or directories
            String contents = readFile(file);
            // get where the package declaration starts
            int packageStart = contents.indexOf("\npackage");
            if (packageStart == -1) { // catch package declarations on the first line
                packageStart = contents.indexOf("package");
            }
            System.out.println(file + "\t " + packageStart);
            try {
                // find the package name as declared in the file
                String packageName = contents.substring(packageStart + 8, contents.indexOf(";"));
                // replace the default WPILibJ path with the ported version
                String cleanContents = contents.replaceAll(WPILIBJ_PATH, PORTED_WPILIBJ_PATH);
                // change the package (and imports) only if we haven't touched it already
                if (!cleanContents.contains(ADDENDUM)) {
                    cleanContents = cleanContents.replaceAll(packageName, CODE_LOCATION + packageName); // "package foo" -> "package code.foo"
                }
                writeToFile(cleanContents, file);
            } catch (StringIndexOutOfBoundsException ex) {
                System.err.println("Error reading " + file + ". \"" + ex.getLocalizedMessage() + "\"");
            }
        } else if (file.isDirectory()) { // go through children and clean them
            for (File child : file.listFiles()) {
                cleanDirectory(child);
            }
        } else {
            // not a java file or a directory, so don't do anything
        }
    }

    /**
     * Writes a string to a given file.
     *
     * @param source The String to write.
     * @param destination The File to write to.
     * @return The edited file.
     */
    private static File writeToFile(String source, File destination) {
        try (PrintWriter writer = new PrintWriter(destination)) {
            writer.println(source + "\n"+ADDENDUM);
            writer.close();
        } catch (FileNotFoundException ex) {
            Logger.getLogger(CodeCleaner.class.getName()).log(Level.SEVERE, null, ex);
        }
        return destination;
    }

    /**
     * Reads the String contents of a text file.
     *
     * @param source The source File to read.
     * @return The String contents of the source file.
     */
    private static String readFile(final File source) {
        try (BufferedReader reader = new BufferedReader(new FileReader(source))) {
            StringBuilder fileData = new StringBuilder(1000);
            char[] buffer = new char[1024];
            for (int numRead = 0; numRead != -1; numRead = reader.read(buffer)) {
                fileData.append(buffer, 0, numRead);
            }
            reader.close();
            return fileData.toString();
        } catch (IOException ex) {
            ex.printStackTrace();
            throw new IllegalArgumentException("Oops, something broke!");
        }
    }

    static void copyDirectory(File source, File target) throws IOException {
        if (source.isDirectory()) {
            if (!target.exists()) {
                target.mkdir();
            }
            String[] children = source.list();
            for (int i = 0; i < children.length; i++) {
                copyDirectory(new File(source, children[i]),
                              new File(target, children[i]));
            }
        } else {
            System.out.println("Copying " + source + " to " + target);
            Files.copy(source.toPath(), target.toPath(), StandardCopyOption.REPLACE_EXISTING);
        }
    }

    // remove this; only used for testing this 
    public static void main(String[] arguments) {
        cleanDirectory(new File("C:\\Users\\Sam\\Desktop\\src"));
    }
}//CodeCleaner -- do not edit this line
//CodeCleaner -- do not edit this line
//CodeCleaner -- do not edit this line
//CodeCleaner -- do not edit this line
//CodeCleaner -- do not edit this line
//CodeCleaner -- do not edit this line

